package com.songyang.yougnsql.core.version;

import com.songyang.yougnsql.common.ErrorMsg;
import com.songyang.yougnsql.common.YoungSQLException;
import com.songyang.yougnsql.core.data.dataItem.DataItem;
import com.songyang.yougnsql.core.utils.ByteUtils;

import java.util.Arrays;

/**
 * @ClassName VersionEntry
 * @Description 该类是versionManager向上一层抽象出来的实体类
 * VersionEntry结构：
 * [XMIN] [XMAX] [data]
 * XMIN 是创建该条记录（版本）的事务编号
 * XMAX 则是删除该条记录（版本）的事务编号
 * data 是dataItem的引用
 * @date 2022/12/16 10:25
 * @Author yanceysong
 * @Version 1.0
 */
public class VersionEntry {
    private static final int OF_XMIN = 0;
    private static final int LEN_PART = 8;
    private static final int OF_XMAX = OF_XMIN + LEN_PART;
    private static final int OF_DATA = OF_XMAX + LEN_PART;
    private long uid;
    private DataItem dataItem;
    private VersionManager versionManager;

    public static VersionEntry newEntry(VersionManager vm, DataItem dataItem, long uid) {
        VersionEntry entry = new VersionEntry();
        entry.uid = uid;
        entry.dataItem = dataItem;
        entry.versionManager = vm;
        return entry;
    }

    /**
     * 打包成为一个VersionEntry
     *
     * @param xid  事务的id
     * @param data 数据
     * @return VersionEntry
     */
    public static byte[] wrapEntryRaw(long xid, byte[] data) {
        byte[] xmin = ByteUtils.long2Byte(xid);
        //byte类型的默认值为0
        byte[] xmax = new byte[8];
        return ByteUtils.concat(xmin, xmax, data);
    }

    /**
     * 通过uid加载一个VersionEntry
     *
     * @param versionManager 版本管理
     * @param uid            uid
     * @return VersionEntry
     * @throws Exception 异常
     */
    public static VersionEntry loadEntry(VersionManager versionManager, long uid) throws Exception {
        DataItem dataItem = ((VersionManagerImpl) versionManager).getDataManager().read(uid);
        if (dataItem == null) throw new YoungSQLException(ErrorMsg.NULL_ENTRY_EXCEPTION);
        return VersionEntry.newEntry(versionManager, dataItem, uid);
    }

    /**
     * 释放entry的缓存
     */
    public void release() {
        ((VersionManagerImpl) versionManager).releaseEntry(this);
    }

    /**
     * 删除
     */
    public void remove() {
        dataItem.release();
    }

    /**
     * 以拷贝的形式返回dataItem中的真实数据
     *
     * @return 数据
     */
    public byte[] data() {
        dataItem.rLock();
        try {
            //这里存的是被包括好的entry的data，需要获取真实的data再解析一下
            byte[] ori = dataItem.data();
            byte[] data = new byte[ori.length - OF_DATA];
            System.arraycopy(ori, 0, data, 0, data.length);
            return data;
        } finally {
            dataItem.rUnLock();
        }
    }

    /**
     * 获取XMin
     *
     * @return XMin
     */
    public long getXMin() {
        dataItem.rLock();
        try {
            byte[] data = dataItem.data();
            return ByteUtils.parseLong(Arrays.copyOfRange(data, OF_XMIN, OF_XMAX));
        } finally {
            dataItem.rUnLock();
        }
    }

    /**
     * 获取XMax
     *
     * @return XMax
     */
    public long getXMax() throws YoungSQLException {
        dataItem.rLock();
        try {
            byte[] data = dataItem.data();
            //每次插入执行插入语句后，data的大小就会变为0，原因未知。
            if (data.length == 0) throw new YoungSQLException(ErrorMsg.UNKNOWN_ERROR);
            return ByteUtils.parseLong(Arrays.copyOfRange(data, OF_XMAX, OF_DATA));
        } finally {
            dataItem.rUnLock();
        }
    }

    /**
     * 设置删除该条记录的xid
     *
     * @param xid xid
     */
    public void setXMax(long xid) {
        dataItem.before();
        try {
            byte[] data = dataItem.data();
            System.arraycopy(ByteUtils.long2Byte(xid), 0, data, OF_XMAX, LEN_PART);
        } finally {
            dataItem.after(xid);
        }
    }

    /**
     * 获取Uid
     *
     * @return Uid
     */
    public long getUid() {
        return this.uid;
    }
}
